﻿using OpenTK;
using OpenTK.Graphics.OpenGL;
 
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace OpenTK_Frame
{
    public class Shader
    {
        private int shaderProgramHandle;    //shader程序句柄

        public Shader(string vertexPath, string fragmentPath)
        {
            if (!File.Exists(vertexPath)) vertexPath = @"./shader/default.vert";
            if (!File.Exists(fragmentPath)) fragmentPath = @"./shader/default.frag";
            //shader代码 
            string vertexShaderCode = GetShaderCode(vertexPath);
            string pixelShaderCode = GetShaderCode(fragmentPath);
            //shader程序建立
            int vertexShaderHandle = GL.CreateShader(ShaderType.VertexShader);
            GL.ShaderSource(vertexShaderHandle, vertexShaderCode);
            GL.CompileShader(vertexShaderHandle);
            //vertexshader 检查 
            string infoLogVert = GL.GetShaderInfoLog(vertexShaderHandle);
            if (infoLogVert != string.Empty) Console.WriteLine(infoLogVert);

            int pixelShaderHandle = GL.CreateShader(ShaderType.FragmentShader);
            GL.ShaderSource(pixelShaderHandle, pixelShaderCode);
            GL.CompileShader(pixelShaderHandle);
            //pixelshader 检查 
            string infoLogFrag = GL.GetShaderInfoLog(pixelShaderHandle);
            if (infoLogFrag != string.Empty) Console.WriteLine(infoLogFrag);

            //生成shader程序
            this.shaderProgramHandle = GL.CreateProgram();
            //对shader程序 加载shader句柄
            GL.AttachShader(this.shaderProgramHandle, vertexShaderHandle);
            GL.AttachShader(this.shaderProgramHandle, pixelShaderHandle);
            //链接shader程序
            GL.LinkProgram(this.shaderProgramHandle);

            //---------------------------------------------
            //卸载句柄
            GL.DetachShader(this.shaderProgramHandle, vertexShaderHandle);
            GL.DetachShader(this.shaderProgramHandle, pixelShaderHandle);
            //清空缓存
            GL.DeleteShader(vertexShaderHandle);
            GL.DeleteShader(pixelShaderHandle);


        }

        public void Use()
        {
            GL.UseProgram(this.shaderProgramHandle);
        }

        public int GetHandle()
        {
            return shaderProgramHandle;
        }

        public void SetMatrix4(string name, Matrix4 mat) {
            int location = GL.GetUniformLocation(this.shaderProgramHandle, name);
            GL.UniformMatrix4(location, true, ref mat);
        }

        /// <summary>
        /// 获得着色器内某个变量的 绑定句柄号 0 1 2 3 等  
        /// 那就不需要在shader内添加 layout(location=0) 了
        /// </summary>
        /// <param name="attribName"></param>
        /// <returns></returns>
        public int GetAttribLocation(string attribName)
        {
            return GL.GetAttribLocation(this.shaderProgramHandle, attribName);
        }

        #region 在shader析构时 做句柄回收机制
        //在shader析构时 做句柄回收机制
        private bool disposedValue = false;
        protected virtual void Dispose(bool disposing)
        {
            if (!disposedValue)
            {
                GL.DeleteProgram(this.shaderProgramHandle);
                disposedValue = true;
            }
        }
        ~Shader()
        {
            GL.DeleteProgram(this.shaderProgramHandle);
        }
        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }
        #endregion

        /// <summary>
        /// 获得shader文本内代码
        /// </summary>
        /// <param name="shaderPath"></param>
        /// <returns></returns>
        public string GetShaderCode(string shaderPath)
        {
            string code = string.Empty;
            using (StreamReader sr = new StreamReader(shaderPath, Encoding.UTF8))
            { code = sr.ReadToEnd(); }
            return code;
        }

    }
}
